﻿#pragma once
#include "SocketClient.h"
#include "MessageParser.h"
#include "ThreadPool.h"
#include "Atom.h"
#include "List.h"
#if (COMM_FEATURE_LIBEVENT==1)

namespace COMM
{
#ifdef COMM_MSVC
	template class COMM_API stdlist<SocketClient*>;
	template class COMM_API List<SocketClient*>;
	template class COMM_API std::list<std::pair<SocketClient*, Buffer*> >;
#endif

	class COMM_API MessageHandler
	{
	public:
		void* m_param_opaque;
		MessageHandler();
		SocketClient* Peer() const;
		MessageParser* Parser() const;
		bool Write(const void* buffer, int size);
		virtual ~MessageHandler(){}
		virtual void OnOpen(){}
		// reason: CONN_EOF(peer shutdown),CONN_ERR(connection error),CONN_SHUTDOWN(close by manual).
		virtual void OnClose(SocketClient::ConnectionState reason){}
		virtual void OnMessage(const char* buffer, int size){}	
	};

	class COMM_API MessageHandlerFactory
	{
	public:
		virtual ~MessageHandlerFactory() {}
		virtual void Release(){ delete this;}
		virtual void DeleteParser(MessageParser* parser){ if(NULL!=parser){ delete parser;} }
		virtual void DeleteHandler(MessageHandler* handler){ if(NULL!=handler){ delete handler;} }
		virtual MessageParser* CreateParser() = 0;
		virtual MessageHandler* CreateHandler() = 0;
	};

	template<class MESSAGEHANDLER, class MESSAGEPARSER=StreamMessageParser>
	class CommMessageHandlerFactory : public MessageHandlerFactory
	{
	public:
		virtual MessageParser* CreateParser(){ return new MESSAGEPARSER;}
		virtual MessageHandler* CreateHandler(){ return new MESSAGEHANDLER;}
	};

	class COMM_API MessageReactor
	{
		MYLIB_NONCOPIED_CLASS(MessageReactor);
	public:
		SocketAcceptor* m_acceptor;
		SocketConnector* m_connector;
		Thread* m_parseThread;
		ThreadPool* m_dispatchThreadPool;
		AtomInt m_handleContinued;
		int m_dispatchIntervalMs;
		MessageHandlerFactory* m_handlerFactory;
		List<SocketClient*> m_clientList;
		ThreadLock m_lockMessage;
		typedef std::list<std::pair<SocketClient*, Buffer*> > MessageList;
		MessageList m_messageList;
		typedef List<SocketClient::Guard*, ThreadNullLock> PeerList;

		MessageReactor(const SocketAddress& address, MessageHandlerFactory* factory, bool asClient=false,
			int dispatchThreadCount=ThreadPool::DefaultThreadsCount, int dispatchIntervalMs=10,
			const char* crtfile=NULL, const char* keyfile=NULL);
		virtual ~MessageReactor(void);
		void Exit();
		// return first one is address is NULL.
		SocketClient::Guard Peer(const char* address = NULL); // prevent SocketClient from deleting.
		void Peers(PeerList& peerList, const char* address_exclude = NULL);
		MessageHandler* Messager(SocketClient* peer);
	};

}

#endif
